package xjh.him.activity;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ImageSpan;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.webkit.MimeTypeMap;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import com.xjh.him.R;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;

import xjh.him.adapter.ChatAdapter;
import xjh.him.bean.ChatBean;
import xjh.him.common.SharedData;
import xjh.him.entity.ChatMsg;
import xjh.him.entity.User;
import xjh.him.netty.codec.Packet;
import xjh.him.netty.dto.ChatMsgDto;
import xjh.him.util.BitmapUtil;
import xjh.him.util.LogcatUtil;


public class ChatActivity extends Activity
        implements Handler.Callback, View.OnClickListener {
    private static final String TAG = "ChatActivity";
    private int page = 1;

    private LinkedList<ChatBean> beans;
    private ChatAdapter adapter;
    private User me, chatter;
    private int screenWidth;
    private int chatId;

    // view
    private SwipeRefreshLayout srl_chat;
    private RecyclerView chat_list;
    private LinearLayoutManager linearLayoutManager;
    private EditText input;

    private static Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);

        // get intent params
        SharedData.updateChatItemHandler = handler;
        Intent intent = getIntent();
        me = SharedData.me;
        chatter = (User) intent.getSerializableExtra("chatter");
        chatId = intent.getIntExtra("chat_id", -1);
        if (chatId == -1) {
            LogcatUtil.w("chat_id not exist");
        }

        // bind view
        input = findViewById(R.id.chat_input);
        ((TextView)findViewById(R.id.chat_page_name)).setText(chatter.getNickname());
        findViewById(R.id.chat_back).setOnClickListener(this);
        findViewById(R.id.icon_plus).setOnClickListener(this);
        findViewById(R.id.chat_send).setOnClickListener(this);

        chat_list = findViewById(R.id.chat_list);
        linearLayoutManager = new LinearLayoutManager(this);
        chat_list.setLayoutManager(linearLayoutManager);
        chat_list.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                if (bottom < oldBottom) {
                    // 当新的 bottom 小于旧的 bottom，说明 recycle_view 被遮挡
                    handler.post(() -> {
                        // 直接调用 scroll 会被软键盘遮挡
                        // 通过 handler 子线程执行则可以实现快速移到底部效果
                        chat_list.scrollToPosition(adapter.getLastPosition());
                    });
                }
            }
        });
        initAdapter(); // 先初始化 adapter
        linearLayoutManager.scrollToPosition(adapter.getLastPosition());
        /*chat_list.addOnScrollListener(new RecyclerView.OnScrollListener() {
            private int firstVisibleItemPos, lastVisibleItemPos;

            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (newState == RecyclerView.SCROLL_STATE_IDLE &&
                        lastVisibleItemPos+1 == adapter.getItemCount()) {
                    LogcatUtil.d("pull up refresh");
                }
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                firstVisibleItemPos = layoutManager.findFirstVisibleItemPosition();
                lastVisibleItemPos = layoutManager.findLastVisibleItemPosition();
            }
        });*/

        srl_chat = findViewById(R.id.srl_chat);
        srl_chat.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            private boolean isRefreshing = false;

            @Override
            public void onRefresh() {
                LogcatUtil.d("pull down refresh");
                if (!isRefreshing) {
                    LogcatUtil.d("do refresh");
                    isRefreshing = true;
                    loadHistoryData();
                    srl_chat.setRefreshing(false);
                    isRefreshing = false;
                }
            }
        });

        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        screenWidth = wm.getDefaultDisplay().getWidth();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            setResult(SharedData.RESULT_CODE_CHAT);
            finish();
        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == SharedData.REQ_CODE_PICTURE && resultCode == RESULT_OK && data != null) {
            Uri imgUri = data.getData();
            ContentResolver resolver = getContentResolver();
            try {
                // 1. fetch img and zoom img bitmap
                Bitmap bitmap = MediaStore.Images.Media.getBitmap(resolver, imgUri);
                bitmap = BitmapUtil.zoom(bitmap, screenWidth * 2 / 5);
                // 2. upload img to server, and write chatMsg to db
                String fileUrl = uploadFile(bitmap, getImageSuffix(imgUri));
                sendChatMsgRemote(SharedData.CHAT_MSG_TYPE_IMAGE, fileUrl);
                // 3. add item to chatList
                adapter.addLast(new ChatBean(me.getId(), "",
                        convertToSpannableString(bitmap),
                        false, SharedData.CHAT_MSG_TYPE_IMAGE));
                smoothScrollToPosition();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else if (requestCode == SharedData.REQ_CODE_CAMERA && resultCode == RESULT_OK && data != null) {
            // 1. fetch img and zoom img bitmap
            Bundle bundle = data.getExtras();
            Bitmap bitmap = (Bitmap) bundle.get("data");
            bitmap = BitmapUtil.zoom(bitmap, screenWidth * 2 / 5);
            // 2. upload img to server, and write chatMsg to db
            String fileUrl = uploadFile(bitmap, ".jpeg");
            sendChatMsgRemote(SharedData.CHAT_MSG_TYPE_IMAGE, fileUrl);
            // 3. add item to chatList
            adapter.addLast(new ChatBean(me.getId(), "",
                    convertToSpannableString(bitmap),
                    false, SharedData.CHAT_MSG_TYPE_IMAGE));
            smoothScrollToPosition();
        }
    }

    private SpannableString convertToSpannableString(Bitmap bitmap) {
        SpannableString text = new SpannableString(" ");
        ImageSpan imageSpan = new ImageSpan(this, bitmap);
        text.setSpan(imageSpan, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        return text;
    }

    private String getImageSuffix(Uri uri) {
        String mimeType = null;
        if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
            mimeType = getContentResolver().getType(uri);
        } else {
            String fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri.toString());
            mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
                    fileExtension.toLowerCase());
        }

        String suffix = null;
        switch (mimeType) {
            case "image/jpeg":
                suffix = ".jpeg";
                break;
            case "image/jpg":
                suffix = ".jpg";
                break;
            case "image/png":
                suffix = ".png";
                break;
        }
        return suffix;
    }

    private String uploadFile(Bitmap bitmap, String suffix) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
        ChatMsgDto.FileUploadReq req = new ChatMsgDto.FileUploadReq();
        req.setBytes(out.toByteArray());
        req.setType(SharedData.CHAT_MSG_TYPE_IMAGE);
        req.setSuffix(suffix);
        SharedData.client.sendMsg(Packet.create(ChatMsgDto.FileUploadReq.class, req));
        Object obj = SharedData.future.get();
        ChatMsgDto.FileUploadResp resp = (ChatMsgDto.FileUploadResp) obj;
        LogcatUtil.d("upload %s success", resp.getFileUrl());
        return resp.getFileUrl();
    }

    public void smoothScrollToPosition() {
        chat_list.smoothScrollToPosition(adapter.getLastPosition());
    }

    public void initAdapter() {
        ChatAdapter chatAdapter = SharedData.CHAT_ADAPTER_MAP.get(chatId);
        if (chatAdapter == null) {
            beans = new LinkedList<>();
            adapter = new ChatAdapter(beans, new HashMap<>());
            loadHistoryData();
            SharedData.CHAT_ADAPTER_MAP.put(chatId, adapter);
        } else {
            beans = chatAdapter.getBeans();
            adapter = chatAdapter;
        }
        chat_list.setAdapter(adapter);
    }

    private void loadHistoryData() {
        LinkedList<ChatBean> insertList = new LinkedList<>();
        ChatMsgDto.SelectPageReq req = new ChatMsgDto.SelectPageReq();
        req.setChatId(chatId);
        req.setPage(page);
        SharedData.client.sendMsg(Packet.create(ChatMsgDto.SelectPageReq.class, req));

        Object obj = SharedData.future.get();
        if (obj instanceof ChatMsgDto.SelectPageResp) {
            ChatMsgDto.SelectPageResp resp = (ChatMsgDto.SelectPageResp) obj;
            page = resp.getPage();
            for (int i=resp.getChatMsgList().size()-1; i>=0; i--) {
                ChatMsg chatMsg = resp.getChatMsgList().get(i);
                insertList.add(
                    new ChatBean(
                        chatMsg.getUserId(),
                        chatMsg.getContent(),
                        new SpannableString(chatMsg.getContent()),
                        chatMsg.getUserId().intValue() == chatter.getId().intValue(),
                        chatMsg.getType())
                );
            }
        }
        HashMap<Integer, User> userMap = new HashMap<>();
        userMap.put(me.getId(), me);
        userMap.put(chatter.getId(), chatter);
        adapter.addAll(insertList);
        adapter.getUserMap().putAll(userMap);
    }

    private void sendChatMsgRemote(byte type, String content) {
        ChatMsgDto.InsertReq req = new ChatMsgDto.InsertReq();
        req.setChatId(chatId);
        req.setUserId(me.getId());
        req.setChatterId(chatter.getId());
        req.setType(type);
        req.setContent(content);
        SharedData.client.sendMsg(Packet.create(ChatMsgDto.InsertReq.class, req));
    }

    public void initPopWindow(View v) {
        View view = LayoutInflater.from(ChatActivity.this).inflate(R.layout.chat_pop_plus, null, false);
        ImageView iconImage = view.findViewById(R.id.icon_image);
        ImageView iconShot = view.findViewById(R.id.icon_shot);

        final PopupWindow popWindow = new PopupWindow(view, WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.WRAP_CONTENT, true);

        // 设置平移动画
        TranslateAnimation animation = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0, Animation.RELATIVE_TO_PARENT, 0,
                Animation.RELATIVE_TO_PARENT, 1, Animation.RELATIVE_TO_PARENT, 0);
        animation.setInterpolator(new AccelerateInterpolator());
        animation.setDuration(200);

        // 保证点击 popWindow 外的区域可以让 popWindow 退出
        // setTouchInterceptor 必须为 false，否则无法 dismiss popWindow
        popWindow.setTouchable(true);
        popWindow.setTouchInterceptor((view1, motionEvent) -> false);

        //要为popWindow设置一个背景才有效
        popWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));

        // 设置 popupWindow 显示的位置
        popWindow.showAtLocation(v, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL,
                0, 0);

        // 设置 popupWindow 里的图片的点击事件
        iconImage.setOnClickListener((v1) -> {
            Intent picture = new Intent(Intent.ACTION_PICK,
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            startActivityForResult(picture, SharedData.REQ_CODE_PICTURE);
            popWindow.dismiss();
        });

        iconShot.setOnClickListener((v2) -> {
            Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(camera, SharedData.REQ_CODE_CAMERA);
            popWindow.dismiss();
        });

        view.startAnimation(animation);
    }

    @Override
    public boolean handleMessage(@NonNull Message msg) {
        switch (msg.what) {
            case SharedData.UPDATE_CHAT_ITEM_MESSAGE:
                ChatMsg chatMsg = (ChatMsg) msg.obj;
                ChatAdapter chatAdapter = SharedData.CHAT_ADAPTER_MAP.get(chatMsg.getChatId());
                if (chatAdapter != null) {
                    chatAdapter.addLast(new ChatBean(
                        chatMsg.getUserId(),
                        chatMsg.getContent(),
                        new SpannableString(chatMsg.getContent()),
                        chatMsg.getUserId().intValue() != SharedData.me.getId().intValue(),
                        chatMsg.getType())
                    );
                    smoothScrollToPosition();
                }
                break;
        }
        return false;
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.chat_send) { // send chat msg
            String text = input.getText().toString();
            if (text.trim().length() > 0) {
                // write to db
                sendChatMsgRemote(SharedData.CHAT_MSG_TYPE_TEXT, text);

                // chatList add item
                adapter.addLast(new ChatBean(me.getId(), "",
                        new SpannableString(text),
                        false, SharedData.CHAT_MSG_TYPE_TEXT));
                input.setText("");
                handler.postDelayed(this::smoothScrollToPosition, 100);
            }
        }else if (v.getId() == R.id.chat_back) { // switch back activity
            if (beans.size() > 0) {
                ChatBean bean = beans.get(beans.size()-1);
                ChatMsg chatMsg = new ChatMsg();
                chatMsg.setChatId(chatId);
                chatMsg.setUserId(bean.getUserId());
                chatMsg.setType(bean.getType());
                chatMsg.setContent(bean.getType() == SharedData.CHAT_MSG_TYPE_TEXT ?
                        bean.getText().toString() : bean.getFileUrl());
                SharedData.msgListAdapter.updateItem(chatMsg);
            }
            setResult(SharedData.RESULT_CODE_CHAT);
            finish();
        }else if (v.getId() == R.id.icon_plus) {
            initPopWindow(v);
        }
    }
}